{-# OPTIONS -Wall #-}

--------------------------------------------------------------------------------
-- |
-- Module      :  Text.PrettyExprHPJ.C99
-- Copyright   :  (c) Stephen Tetley 2012
-- License     :  BSD3
--
-- Maintainer  :  stephen.tetley@gmail.com
-- Stability   :  unstable
-- Portability :  GHC
--
-- Common C operator pretty printers with associated fixity and
-- associativity.
--
--------------------------------------------------------------------------------

module Text.PrettyExprHPJ.C99
  (
  -- * Unparse a DocE
    unparse

  -- * C operators

  -- ** Precedence 16
  , directSelectionU
  , indirectSelectionU
  , postIncrU
  , postDecrU

  -- ** Precedence 15
  , preIncrU
  , preDecrU
  , bitwiseNotU
  , logicalNotU
  , plusU
  , negateU
  , addressOfU
  , indirectionU

  -- ** Precedence 13
  , multiplyB
  , divideB
  , moduloB

  -- ** Precedence 12
  , addB
  , subtractB

  -- ** Precedence 11
  , leftShiftB
  , rightShiftB

  -- ** Precedence 10
  , lessThanB
  , greaterThanB
  , lessThanEqB
  , greaterThanEqB

  -- ** Precedence 9
  , equalB
  , notEqualB

  -- ** Precedence 8
  , bitwiseAndB

  -- ** Precedence 7
  , bitwiseXorB

  -- ** Precedence 6
  , bitwiseOrB

  -- ** Precedence 5
  , logicalAndB

  -- ** Precedence 4
  , logicalOrB

  -- ** Precedence 3
  , conditionalT

  -- ** Precedence 2
  , assignB
  , mulAssignB
  , divAssignB
  , modAssignB
  , addAssignB
  , subAssignB
  , leftShiftAssignB
  , rightShiftAssignB
  , bitwiseAndAssignB
  , bitwiseOrAssignB
  , bitwiseXorAssignB

  -- ** Precedence 1
  , commaN

  ) where

import Text.PrettyExprHPJ

import Text.PrettyPrint.HughesPJ                -- pacakge: pretty


-- | Run an unparser for C-like language expressions.
-- 
-- C99 has maximum precedence of 16.
--
unparse :: DocE -> Doc
unparse = unparser $ makeUnparser 16


--------------------------------------------------------------------------------
-- Precedence 16

-- | direct selection - the second argument is the selection
-- identifier (a name not an expression).
-- 
-- > . (postfix 16)
--
directSelectionU        :: DocE -> String -> DocE
directSelectionU d s    = Unary (postfix 16) (noSpace $ '.' : s) d


-- | indirect selection - the second argument is the selection
-- identifier (a name not an expression).
-- 
-- > -> (postfix 16) --
--
indirectSelectionU      :: DocE -> String -> DocE
indirectSelectionU d s  = Unary (postfix 16) (noSpace $ "->" ++ s) d


-- | Postfix increment.
-- 
-- > ++ (postfix 16)
--
postIncrU               :: DocE -> DocE
postIncrU               = Unary (postfix 16) (noSpace "++")

-- | Postfix decrement.
-- 
-- > -- (postfix 16)
--
postDecrU               :: DocE -> DocE
postDecrU               = Unary (postfix 16) (noSpace "--")


--------------------------------------------------------------------------------
-- Precedence 15


-- | Prefix increment.
-- 
-- > ++ (prefix 15)
--
preIncrU                :: DocE -> DocE
preIncrU                = Unary (prefix 15) (noSpace "++")


-- | Prefix decrement.
-- 
-- > -- (prefix 15)
--
preDecrU                :: DocE -> DocE
preDecrU                = Unary (prefix 15) (noSpace "--")


-- | Bitwise not.
-- 
-- > ~ (prefix 15)
--
bitwiseNotU             :: DocE -> DocE
bitwiseNotU             = Unary (prefix 15) (noSpace "~")


-- | Logical not.
-- 
-- > ! (prefix 15)
--
logicalNotU             :: DocE -> DocE
logicalNotU             = Unary (prefix 15) (noSpace "!")


-- | Plus (unary plus).
-- 
-- > + (prefix 15)
--
plusU                   :: DocE -> DocE
plusU                   = Unary (prefix 15) (noSpace "+")


-- | Arithmetic negation.
-- 
-- > - (prefix 15)
--
negateU                :: DocE -> DocE
negateU                = Unary (prefix 15) (noSpace "-")


-- | Address of.
-- 
-- > & (prefix 15)
--
addressOfU              :: DocE -> DocE
addressOfU              = Unary (prefix 15) (noSpace "&")

-- | Indirection.
-- 
-- > * (prefix 15)
--
indirectionU            :: DocE -> DocE
indirectionU            = Unary (prefix 15) (noSpace "*")

--------------------------------------------------------------------------------
-- Precedence 13

-- | Multiplication.
-- 
-- > * (infixl 13)
--
multiplyB               :: DocE -> DocE -> DocE
multiplyB               = Binary (infixL 13) (noSpace "*")

-- | Division.
-- 
-- > / (infixl 13)
--
divideB                 :: DocE -> DocE -> DocE
divideB                 = Binary (infixL 13) (noSpace "/")


-- | Modulus.
-- 
-- > % (infixl 13)
--
moduloB                 :: DocE -> DocE -> DocE
moduloB                 = Binary (infixL 13) (noSpace "%")



--------------------------------------------------------------------------------
-- Precedence 12

-- | Addition.
-- 
-- > + (infixl 12)
--
addB                    :: DocE -> DocE -> DocE
addB                    = Binary (infixL 12) (noSpace "+")

-- | Subtraction.
-- 
-- > - (infixl 12)
--
subtractB               :: DocE -> DocE -> DocE
subtractB              = Binary (infixL 12) (noSpace "-")


--------------------------------------------------------------------------------
-- Precedence 11

-- | Left shift.
-- 
-- > << (infixl 11)
--
leftShiftB              :: DocE -> DocE -> DocE
leftShiftB              = Binary (infixL 11) (noSpace "<<")

-- |  Right shift.
-- 
-- > >> (infixl 11)
--
rightShiftB             :: DocE -> DocE -> DocE
rightShiftB             = Binary (infixL 11) (noSpace ">>")



--------------------------------------------------------------------------------
-- Precedence 10

-- | Less than.
-- 
-- > < (infixl 10)
--
lessThanB               :: DocE -> DocE -> DocE
lessThanB               = Binary (infixL 10) (spaced "<")


-- | Less than or equal.
-- 
-- > <= (infixl 10)
--
lessThanEqB             :: DocE -> DocE -> DocE
lessThanEqB             = Binary (infixL 10) (spaced "<=")



-- | Greater than.
-- 
-- > > (infixl 10)
--
greaterThanB            :: DocE -> DocE -> DocE
greaterThanB            = Binary (infixL 10) (spaced ">")


-- | Greater than or equal.
-- 
-- > >= (infixl 10)
--
greaterThanEqB          :: DocE -> DocE -> DocE
greaterThanEqB          = Binary (infixL 10) (spaced ">=")



--------------------------------------------------------------------------------
-- Precedence 9

-- | Equality.
-- 
-- > == (infixl 9)
--
equalB                  :: DocE -> DocE -> DocE
equalB                  = Binary (infixL 9) (spaced "==")


-- | Inequality.
-- 
-- > != (infixl 9)
--
notEqualB               :: DocE -> DocE -> DocE
notEqualB               = Binary (infixL 9) (spaced "!=")



--------------------------------------------------------------------------------
-- Precedence 8


-- | Integer bitwise AND.
-- 
-- > & (infixl 8)
--
bitwiseAndB             :: DocE -> DocE -> DocE
bitwiseAndB             = Binary (infixL 8) (spaced "&")



--------------------------------------------------------------------------------
-- Precedence 7


-- | Integer bitwise XOR.
-- 
-- > ^ (infixl 7)
--
bitwiseXorB             :: DocE -> DocE -> DocE
bitwiseXorB             = Binary (infixL 7) (spaced "^")


--------------------------------------------------------------------------------
-- Precedence 6


-- | Integer bitwise OR.
-- 
-- > | (infixl 6)
--
bitwiseOrB              :: DocE -> DocE -> DocE
bitwiseOrB              = Binary (infixL 6) (spaced "|")


--------------------------------------------------------------------------------
-- Precedence 5

-- | Logical and.
-- 
-- > && (infixl 5)
--
logicalAndB             :: DocE -> DocE -> DocE
logicalAndB             = Binary (infixL 5) (spaced "&&")


--------------------------------------------------------------------------------
-- Precedence 4

-- | Logical or.
-- 
-- > || (infixl 4)
--
logicalOrB              :: DocE -> DocE -> DocE
logicalOrB              = Binary (infixL 4) (spaced "||")

--------------------------------------------------------------------------------
-- Precedence 3

-- | Conditional.
-- 
-- > ? : (ternary 3)
--
conditionalT              :: DocE -> DocE -> DocE -> DocE
conditionalT              = Ternary (infixR 2) (spaced "?") (spaced ":")



--------------------------------------------------------------------------------
-- Precedence 2

-- | Assignment.
-- 
-- > = (infixr 2)
--
assignB                 :: DocE -> DocE -> DocE
assignB                 = Binary (infixR 2) (spaced "=")


-- | Assignment with multiplication.
-- 
-- > *= (infixr 2)
--
mulAssignB              :: DocE -> DocE -> DocE
mulAssignB              = Binary (infixR 2) (spaced "*=")


-- | Assignment with division.
-- 
-- > /= (infixr 2)
--
divAssignB              :: DocE -> DocE -> DocE
divAssignB              = Binary (infixR 2) (spaced "/=")


-- | Assignment with modulo.
-- 
-- > %= (infixr 2)
--
modAssignB              :: DocE -> DocE -> DocE
modAssignB              = Binary (infixR 2) (spaced "%=")


-- | Assignment with addition.
-- 
-- > += (infixr 2)
--
addAssignB              :: DocE -> DocE -> DocE
addAssignB              = Binary (infixR 2) (spaced "+=")


-- | Assignment with subtraction.
-- 
-- > -= (infixr 2)
--
subAssignB              :: DocE -> DocE -> DocE
subAssignB              = Binary (infixR 2) (spaced "-=")


-- | Assignment with left shift.
-- 
-- > <<= (infixr 2)
--
leftShiftAssignB        :: DocE -> DocE -> DocE
leftShiftAssignB        = Binary (infixR 2) (spaced "<<=")


-- | Assignment with signed right shift.
-- 
-- > >>= (infixr 2)
--
rightShiftAssignB       :: DocE -> DocE -> DocE
rightShiftAssignB       = Binary (infixR 2) (spaced ">>=")


-- | Assignment with bitwise and.
-- 
-- > &= (infixr 2)
--
bitwiseAndAssignB       :: DocE -> DocE -> DocE
bitwiseAndAssignB       = Binary (infixR 2) (spaced "&=")


-- | Assignment with bitwise xor.
-- 
-- > ^= (infixr 2)
--
bitwiseXorAssignB       :: DocE -> DocE -> DocE
bitwiseXorAssignB       = Binary (infixR 2) (spaced "^=")


-- | Assignment with bitwise or.
-- 
-- > |= (infixr 2)
--
bitwiseOrAssignB        :: DocE -> DocE -> DocE
bitwiseOrAssignB        = Binary (infixR 2) (spaced "|=")


--------------------------------------------------------------------------------
-- Precedence 1



-- | Sequential evaluation.
--
-- > , (n-ary, infixl 1)
-- 
-- Note - Harbison and Steele identify the comma operator as
-- left-to-right rather than non-associative.
commaN                  :: [DocE] -> DocE
commaN                  = Nary (infixL 1) (noSpace ", ")
